/**
 * Copyright (c) 2011-2013, dafei 李飞 (myaniu AT gmail DOT com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package cn.hpclub.server.security;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.ext.plugin.shiro.ShiroMethod;

import cn.dreampie.shiro.core.SubjectKit;
import cn.dreampie.shiro.core.handler.AuthzHandler;

public class MyShiroInterceptor implements Interceptor{
    // @Fields CLIENT :

    private static final String CLIENT = "/api/v1/";
    private static final Logger log    = LoggerFactory.getLogger(MyShiroInterceptor.class);

    /**
     * 权限检查
     *
     * @param ai
     * @param ahs
     * @return
     */
    private boolean assertNoAuthorized(Invocation ai, List<AuthzHandler> ahs){
        // 存在访问控制处理器。
        if(ahs != null && ahs.size() > 0){
            // 没有登录则跳转到登录页面
            if(ShiroMethod.notAuthenticated()){
                ai.getController().redirect("/admin/login");
                return true;
            }
            // 登录前访问页面缓存
            if(!SubjectKit.isAuthed()){
                WebUtils.saveRequest(ai.getController().getRequest());
            }

            // rememberMe自动登录
            Subject subject = SubjectKit.getSubject();
            if(!subject.isAuthenticated() && subject.isRemembered()){
                Object principal = subject.getPrincipal();
                if(principal == null){
                    SubjectKit.getSubject().logout();
                }
            }

            try{
                // 执行权限检查。
                for(AuthzHandler ah : ahs){
                    ah.assertAuthorized();
                }
            }
            catch(UnauthenticatedException lae){
                // RequiresGuest，RequiresAuthentication，RequiresUser，未满足时，抛出未经授权的异常。
                // 如果没有进行身份验证，返回HTTP401状态码
                ai.getController().renderError(401);
                return true;
            }
            catch(AuthorizationException ae){
                // RequiresRoles，RequiresPermissions授权异常
                // 如果没有权限访问对应的资源，返回HTTP状态码403。
                ai.getController().renderError(403);
                return true;
            }
            catch(Exception e){
                // 出现了异常，应该是没有登录。
                ai.getController().renderError(401);
                return true;
            }
        } else{
            // /*
            // * 增加白名单，除白名单外的URL都拦截.白名单设置位置:
            // * WebRoot\WEB-INF\classes\serverConfig.properties
            // */
            // if(UrlWhiteList.getInstance().isInWhiteList(ai.getActionKey())){
            // /* 白名单URL不拦截 */
            // log.info("url in whiteList:" + ai.getActionKey());
            // return false;
            // } else{
            // log.info("url is not in whiteList:" + ai.getActionKey() + ",show
            // 403 error");
            // ai.getController().renderError(403);
            // }
        }
        return false;
    }

    /**
     * @param inv
     * @see com.jfinal.aop.Interceptor#intercept(com.jfinal.aop.Invocation)
     */
    @Override
    public void intercept(Invocation inv){
        Method method;
        try{
            Class<?> shiroKitClass = Class.forName("cn.dreampie.shiro.core.ShiroKit");
            method = shiroKitClass.getDeclaredMethod("getAuthzHandler", HttpServletRequest.class, String.class);
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            List<AuthzHandler> authzList = (List<AuthzHandler>)method
                    .invoke(shiroKitClass, inv.getController().getRequest(), inv.getActionKey());
            // 路径权限 //注解权限
            // 权限验证
            if(assertNoAuthorized(inv, authzList)){
                return;
            }

            // 执行正常逻辑
            inv.invoke();
        }
        catch(NoSuchMethodException e){
            e.printStackTrace();
        }
        catch(SecurityException e){
            e.printStackTrace();
        }
        catch(IllegalAccessException e){
            e.printStackTrace();
        }
        catch(IllegalArgumentException e){
            e.printStackTrace();
        }
        catch(InvocationTargetException e){
            e.printStackTrace();
        }
        catch(ClassNotFoundException e){
            e.printStackTrace();
        }

    }
}
